from java.awt import *
from javax.swing import *
import javax
import java
import MatrixIO,NCA,figure
from java.lang import ClassLoader,Math
from console import *
import java.io as io
import org
import org.python.util as util
import javaRbioconductor
from ActionListeners import PyAction
import copy
from Matrix import Matrix
import cern
import com
import net.miginfocom.swing.MigLayout as MigLayout
import Affy

# time to finish this thing!

def convertIDs(console):
	try:
		Elabels=console.getVar('Elabels')
		x = NCA.convertIDs(Elabels)
		w = filter(lambda x: x is not None, x)
		if len(w)>10:
			console.putVar({'Elabels':x})
			console.doInBackground('E.rowNames=Elabels;');
			print "#Found a conversion for Elabels\n"
	except:
		pass
		


def tileWin(e,desktop):
	frames = desktop.getAllFrames()
	dBounds = desktop.getBounds()
	cols = int(Math.sqrt(len(frames)))
	rows = int(Math.ceil( len(frames) / cols))
	lastRow = len(frames) - cols*(rows-1)
	if ( lastRow == 0 ):
		rows-=1;
		height = dBounds.height / rows;
	else:
		height = dBounds.height / rows;
		if ( lastRow < cols ):
			rows-=1;
			width = dBounds.width / lastRow;
			for i in range(0,int(lastRow)):
				frames[cols*rows+i].setBounds( i*width, rows*height,
											   width, height );
			
	width = dBounds.width/cols;
	for j in range(0,rows):
		for i in range(0,cols):
			frames[i+j*cols].setLocation( i*width, j*height)
#										width, height );

def cascadeWin(e,desktop):
	frames = desktop.getAllFrames()
	dBounds = desktop.getBounds()
	for i in range(0,len(frames)):
		separation=10
		if i>0:
			separation = separation + frames[i-1].width;
		frames[i].setLocation( dBounds.x+separation, 10 + dBounds.y)

def loadCEL(console):
	print "called loadCEL"
	x = JInternalFrame()
	fc = JFileChooser()
	fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY)
	x.getContentPane().add(fc)
	returnVal = fc.showOpenDialog(x);
	x.pack()
	x.show()
	console.desktop.add(x)


	
	if returnVal == JFileChooser.APPROVE_OPTION:
		f = JInternalFrame('pbar')
		p = JProgressBar()
		p.setIndeterminate(True)
		p.show()
		f.add(p)
		console.desktop.add(f)
		f.show()
		dirname = fc.getSelectedFile().getAbsolutePath()
		es = Affy.ExpressionSet(dirname,console)
		es.readcdf()
		E = es.processCEL()  # need to wait on this.
		print "created expressionset\n"
		Elabels = es.PSIDX.keys()
		Explabels=None
		console.putVar({'E':E,'Elabels':Elabels,'ExpLabels':Explabels,'ExpressionSet':es})
		print "done"

def ProcessMicroarrayDirectory(console):
	#x = JInternalFrame();
	print "called ProcessMicroarrayDirectory"
	x = com.explodingpixels.macwidgets.HudWindow('Expression Data')
	
	Button0 = JButton('Load CEL data')
	Button1 = JButton('Q-Norm and Probe Set Summarization')
	Button2 = JButton('Convert Probe Sets to Gene Names')
	Button3 = JButton('Build PS or Gene Specific Log-Ratios')



	Button0.actionPerformed = lambda e: loadCEL(console)
	Button1.actionPerformed = lambda e: console.doInBackground('import NCA; T=NCA.qnorm(E); import Affy; E = Affy.summarize(T,Elabels,ExpressionSet);')
##	Button2.actionPerformed = 
	Button3.actionPerformed = lambda e: FrontAndCenterMatrix(console)  
## get the current table and column selection, if not prompt for user selection


	x.getContentPane().add(Button0)
	x.getContentPane().add(Button1)
	x.getContentPane().add(Button2)
	x.getContentPane().add(Button3)
	x.getJFrame().pack()
	x.getJFrame().show()
		

def FrontAndCenterMatrix(console):
	
	try:
		console.getVar('refColumn')
	except:
		JOptionPane.showMessageDialog(console.desktop,'Please select a column in the signal matrix to use as reference, and Retry.');
		return
	
	cmdString = 'Eorig=Matrix(E);E = logRatios(E,refColumn,True);'
	console.doInBackground(cmdString)
	
	


def loadMicroarray(console):
	x = com.explodingpixels.macwidgets.HudWindow('Expression Data')
	#x  = JInternalFrame()
	
	dirButton = JButton('Process Affymetrix Data')
	sButton = JButton('Process a Single Array File')
	top = JPanel(GridLayout(2,1));
	bottom = JPanel(GridLayout(2,1))

	top.add(dirButton)
	top.add(sButton)

	whole = JPanel(GridLayout(2,1))
	whole.add(top)
	whole.add(bottom)

	refButton= JButton('Select Reference Column & Normalize By Reference')
	refButton.setEnabled(True)
	refButton.actionPerformed = lambda e: FrontAndCenterMatrix(console)  ## get the current table and column selection, if not prompt for user selection
 	bottom.add(refButton)
 	
 	cButton= JButton('Convert Identifiers')
 	cButton.setEnabled(True)
	cButton.actionPerformed = lambda e: convertIDs(console)
 	bottom.add(cButton)
 	

	x.getContentPane().add(whole)
	sButton.actionPerformed = lambda e:loadMicroarrayFile(console)
	dirButton.actionPerformed = lambda e:ProcessMicroarrayDirectory(console)
	x.getJFrame().pack()
	x.getJFrame().show()
	#console.desktop.add(x)


def loadMicroarrayFile(console):
	x = JInternalFrame();
	filter = javax.swing.filechooser.FileNameExtensionFilter("Tab delimited Text Files or Excel Files", ["txt","xls"])
	fc = JFileChooser()
	fc.addChoosableFileFilter(filter)
	x.getContentPane().add(fc)
	returnVal = fc.showOpenDialog(x);
	x.pack()
	x.show()
	if returnVal == JFileChooser.APPROVE_OPTION:
		console.putVar({'filename':fc.getSelectedFile().getAbsolutePath()})
		if fc.getSelectedFile().getAbsolutePath().endswith('xls'):
			console.doInBackground('[E,Elabels,Explabels]=readExcel(filename,console.progressMan);view(E);');
		else:
			console.doInBackground('[E,Elabels,Explabels]=readmatrix(filename,console.progressMan);E.varname="E";f=view(E);');
	
def loadConnectivity(e,console):
	x  = JInternalFrame()
	fc = JFileChooser()
	x.getContentPane().add(fc)
	returnVal = fc.showOpenDialog(x);
	x.pack()
	x.show()
	if returnVal == JFileChooser.APPROVE_OPTION:
		console.putVar({'filename':fc.getSelectedFile().getAbsolutePath()})
		if fc.getSelectedFile().getAbsolutePath().endswith('xls'):
			console.doInBackground('[A,Alabels,Plabels]=readExcel(filename,console.progressMan);view(A);');
		else:
			console.doInBackground('[A,Alabels,Plabels]=readmatrix(filename,"connectivity",console.progressMan,True);A.varname="A";f=view(A);tfs=range(1,len(Plabels));');

def newMenu(e,console):
	pass

	
def saveExcelMenu(e,console):
	fc = javax.swing.JFileChooser();
	fc.setCurrentDirectory (java.io.File ("."));
	result = fc.showSaveDialog(fc);
	response=''
	if (result == javax.swing.JFileChooser.CANCEL_OPTION):
		return True;
	elif (result == javax.swing.JFileChooser.APPROVE_OPTION):
		fFile = fc.getSelectedFile();
		if (fFile.exists()):
			response = javax.swing.JOptionPane.showConfirmDialog (None,"Overwrite existing file?","Confirm Overwrite",javax.swing.JOptionPane.OK_CANCEL_OPTION,javax.swing.JOptionPane.QUESTION_MESSAGE);
			if (response == JOptionPane.CANCEL_OPTION): 
		   		return false;
		   	
		# get data from console
		console.putVar({'xlsfile':fFile.getAbsolutePath()})
		console.doInBackground('import MatrixIO;MatrixIO.writeMatExcel(xlsfile,a,p)')


def saveMenu(e,console):
	fc = javax.swing.JFileChooser();
	fc.setCurrentDirectory (java.io.File ("."));
	result = fc.showSaveDialog(fc);
	response=''
	if (result == javax.swing.JFileChooser.CANCEL_OPTION):
		return True;
	elif (result == javax.swing.JFileChooser.APPROVE_OPTION):
		fFile = fc.getSelectedFile();
		if (fFile.exists()):
			response = javax.swing.JOptionPane.showConfirmDialog (None,"Overwrite existing file?","Confirm Overwrite",javax.swing.JOptionPane.OK_CANCEL_OPTION,javax.swing.JOptionPane.QUESTION_MESSAGE);
			if (response == JOptionPane.CANCEL_OPTION): 
		   		return False;

		me={}
		for x in console.interp.locals.items():
			t=x[1]
			print x[0]
			try:
		
				if isinstance(t,org.python.core.PyList):
		 			idx = copy.deepcopy(x[0])
					me[idx]=copy.deepcopy(t)
					
				elif isinstance(t,cern.colt.matrix.DoubleMatrix2D):
					#print "found matrix"
					idx = copy.deepcopy(x[0])
					m=Matrix(x[1]._M.copy())
					m.columnNames = copy.deepcopy(x[1].columnNames)
					m.rowNames = copy.deepcopy(x[1].rowNames)
					me[idx]=m
			except:
				print "Error:  Could not save ", x[0]
		
		outFile = io.FileOutputStream(fFile)
		outStream = io.ObjectOutputStream(outFile)
		outStream.writeObject(me)
		outFile.close()
		outStream.close()
		print "Saved Workspace to file: ", fFile, "\n"


def openMenu(e,console):
	fc = javax.swing.JFileChooser();
	fc.setCurrentDirectory (java.io.File ("."));
	result = fc.showOpenDialog(fc);
	response=''
	if (result == javax.swing.JFileChooser.CANCEL_OPTION):
		return True;
	elif (result == javax.swing.JFileChooser.APPROVE_OPTION):
		fFile = fc.getSelectedFile();
		# get data from console
		
		inFile = io.FileInputStream(fFile)
		try:
			inStream = util.PythonObjectInputStream(inFile)
		except:
			print "Error, workspace created with an older version of NCA"
			return

		intemp= inStream.readObject()
		print "before update"			
		console.interp.locals.update(intemp)
		print "after update"
		inFile.close()
		print "Reading saved workspace from file:", fFile,"\n"
	
def helpMenu(e,console):
	JMenu()
	# add hooks
	pass		

def analysisMenu(e,console):
	pass

def Match(e,console):
	console.doInBackground('(E0,A0,gene_ids,tfas)=Match(E,Elabels,A,Alabels)')
	pass

def ncahook(console,e):
	console.doInBackground('(a,p,pdev,ax,px)=statsnca(Ef,Af,10,None);p.varname="p";')
	console.doInBackground('(arand,prand,pdevrand,arx,prx)=statsnca(Ef,Af,10,True,E);')
	
def affyhook(console):
	pass
	#print load qnorm
	
def plotMenu(console):
	Plabels=console.getVar('Plabels')
	f = JInternalFrame('Select Regulator');		
	jc = JList(Plabels);
	js = JScrollPane(jc)
	jb = JButton('Plot')
	jb.setActionCommand("plot")
	p = JSplitPane(JSplitPane.VERTICAL_SPLIT,js,jb);
	f.add(p)
	
	jb.addActionListener( figure.PyAction(jc,console) )	
	f.setSize(200,600);
	p.setDividerLocation(520);
	f.show()
	f.setClosable(True)
	console.desktop.add(f);

def menuBar(rconsole):

	menus=[];
	menubar = JMenuBar();
	filemenu=[];
		
	fileMenuTitles = {"New": lambda e: newMenu(e,rconsole),"Load Workspace": lambda e: openMenu(e,rconsole),"Save Workspace": lambda e: saveMenu(e,rconsole),"Save TFAs As Excel": lambda e: saveExcelMenu(e,rconsole),"Quit": lambda e: e}
	for x in fileMenuTitles:
		w = JMenuItem(x)
		w.actionPerformed = fileMenuTitles[x]
		filemenu += [w]
		
	mtop = ["File","Network Analysis","Visualization","Help"]
	menus=map(JMenu, mtop);
	map(menus[0].add,filemenu)  # add file submenu to main menu

	viewA = lambda e: rconsole.doInBackground('view(A);')
	viewE = lambda e: rconsole.doInBackground('view(E);')
	viewP = lambda e: rconsole.doInBackground('view(p);')
	viewCS = lambda e: rconsole.doInBackground('view(a);')
	heatP = lambda e: rconsole.doInBackground('heatmap(p)')
	heatE = lambda e: rconsole.doInBackground('heatmap(E)')
	netviz = lambda e: networkView(e,rconsole.desktop)
	connMap = lambda e: TFnetworkView(e,rconsole.desktop)
	sigTFs = lambda e: rconsole.doInBackground('sTFs=sigTFs(p,prx);sTFs.rowNames=p.rowNames;sTFs.columnNames=[""] +p.columnNames;heatmap(sTFs);print sTFs;view(sTFs);')	
	matchMatrix = lambda e: rconsole.doInBackground('(E0,A0,gene_ids,tfas)=Match(E,Elabels,A,Alabels,Plabels)')
	runNCA = lambda e: ncahook(rconsole,e);
	selectTFs = lambda e: rconsole.doInBackground('select_TFs(Plabels);');
	ratioBuilder = lambda x: str('funct')
	cascadeHook = lambda e: cascadeWin(e,rconsole.desktop)
	loadArray = lambda x : loadMicroarray(x,rconsole)
	dwiz = lambda x : affyhook(rconsole.desktop);
	plotTFAs = lambda x : plotMenu(rconsole);	
	vmenus={'Significant TFAs':sigTFs,'Cascade Windows':cascadeHook,'View A Matrix':viewA,'View E Matrix':viewE, 'View CS Values':viewCS, 'View TFAs':viewP,'Compute Significant TFAs':sigTFs,'Plot TFAs':plotTFAs}
	vmenu=[];
	
	for x in vmenus:
		w = JMenuItem(x)
		w.actionPerformed = vmenus[x]
		vmenu += [w]
	vmenu.sort()
	map(menus[2].add,vmenu);
	temp=[]
	analysis_items = {'Convert Identifiers':lambda e: convertIDs(rconsole),"Run Affymetrix Data Wizard":dwiz,"Select TFs to Analyze":selectTFs,"Load Signal Data":loadArray, "Load Network Data":lambda x: loadConnectivity(x,rconsole), "Match Data":matchMatrix,"Run NCA":runNCA }
	for x in analysis_items:
		w = JMenuItem(x)
		w.actionPerformed = analysis_items[x]
		temp += [w]
	map(menus[1].add,temp) 
	map(menubar.add,menus)
	return menubar


def buildWizard(rconsole):
	#f = JInternalFrame('Network Component Analysis Wizard')
	f = com.explodingpixels.macwidgets.HudWindow('NCA Overview')
	# add everything we need to f
	p = JPanel(MigLayout());

	matchMatrix = lambda e: rconsole.doInBackground('(E0,A0,gene_ids,tfas)=Match(E,Elabels,A,Alabels,Plabels)')
	runNCA = lambda e: ncahook(rconsole,e);
	selectTFs = lambda e: rconsole.doInBackground('select_TFs(Plabels);');

	##dataWizard( loadArray )
	buttons_items = [{"Step 1: Upload Signal Data":lambda x : loadMicroarray(rconsole)},{"Step 2: Load Network Data":lambda x: loadConnectivity(x,rconsole)}, {"Step 3: Match Data":matchMatrix}, {"Step 4: Select TFs to Analyze":selectTFs}, {"Step 5: Run NCA":runNCA }]
	temp=[]
	for x in buttons_items:
		for y in x:
			w = JButton(y)
			w.setHorizontalAlignment(JButton.CENTER) 
			w.actionPerformed = x[y]
			temp += [w]
	map(lambda x: p.add(x,"wrap"),temp) 
	f.getContentPane().add(p)
	return f
	
	# remember to add window option to show/hide console.
	


class Desktop(JDesktopPane):
	
	##sPanel = lambda x,y,z : Search.SearchPanel(x,y,z)
	toolbar = None
	console = None

	def __init__(self):
		JDesktopPane.__init__(self)
		self.setBackground(java.awt.Color.GRAY)

	
	def registerViz(self,v,frame):
		self.sPanel = self.sPanel(v.getVisualization(),frame)

	

class WinApp(java.lang.Object):
	desktop = None;
	
	def __init__(self):
		cl=java.lang.Thread.currentThread().getContextClassLoader();
		namespace=None;
		self.desktop = Desktop()
		desktop = self.desktop
		dscroll = JScrollPane(desktop,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS)
		self.desktop.console = Console(desktop)
		console = self.desktop.console
		console_frame = JInternalFrame()
		console_frame.getContentPane().add(JScrollPane(console.text_pane))
		console_frame.getContentPane().setSize(200,300)
		desktop.add(console_frame)		
		console_frame.getContentPane().show()

		console_frame.setResizable(True);
		#console_frame.setClosable(True);
		#console_frame.setMaximizable(True);
		console_frame.show()
		console_frame.setSize(java.awt.Dimension(400,600))
		console_frame.setLocation(725,127);
		
		menubar = menuBar(console);
		flowframe = buildWizard(console);
		#flowframe.getJFrame().setResizable(True);
		#flowframe.getJFrame().setClosable(False);
		#flowframe.getJFrame().setMaximizable(True);
	#	flowframe.pack()
		flowframe.getJFrame().setSize(java.awt.Dimension(266,272))
		flowframe.getJFrame().setLocation(197,103)
		flowframe.getJFrame().show()
	#	desktop.add(flowframe)
		helpbox = javax.swing.JSeparator()
		desktop.setSize(200,100)
		desktop.show()

		app = JFrame();
		#mc.makeWindowLeopardStyle(app.getRootPane())
		cl = app.getClass().getClassLoader();
	 	app.setIconImage(javax.swing.ImageIcon('icons/nca.png').getImage())
		app.setTitle('Network Component Analysis')
		app.setJMenuBar(menubar);
		app.pack()
		app.setState(JFrame.NORMAL);
		app.getContentPane().add(dscroll)
		toolkit = Toolkit.getDefaultToolkit();
		dimension = toolkit.getScreenSize();
		app.setSize(dimension);
	
		app.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
		app.setVisible(True);
	
if __name__ == '__main__':
	w=WinApp();
	
